﻿using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using ApplLogic.ApplClasses;
using ConnectionObjects;
using Entities;
using ApplLogic.LogicalServices;

namespace ApplLogic.Server
{
    public abstract class ClientComunicationHandler
    {
        protected TcpClient m_Client;
        protected NetworkStream m_ClientStream;
        protected int m_ClientNumber;
        protected ApplRequestHandlerAbstract m_ApplRequestHandler;
        protected MethodExecuter m_MethodExecuter = null;
        
        public ClientComunicationHandler(){}

        public ClientComunicationHandler(TcpClient client ,int clientNumber, ApplRequestHandlerAbstract applRequestHandler)
        {
            m_Client = client;
            m_ClientStream = client.GetStream();
            m_ClientNumber = clientNumber;
            m_ApplRequestHandler = applRequestHandler;
        }

        public int ClientNumber
        {
            get { return m_ClientNumber; }
            set { m_ClientNumber = value; } 
        }

        public TcpClient Client 
        {
            get { return m_Client; }
            set { m_Client = value; } 
        }

        public NetworkStream ClientStream 
        {
            get { return m_ClientStream; }
            set { m_ClientStream = value; } 
        }

        public ApplRequestHandlerAbstract ApplRequestHandler
        {
            get { return m_ApplRequestHandler; }
            set { m_ApplRequestHandler = value; }
        }

        public void HandleClientComm()
        {
            byte[] message = new byte[4096];
            int bytesRead = 0;
            InConnectionObject inObject = null;
            while (true)
            {
                try
                {
                    inObject = (InConnectionObject)(new BinaryFormatter().Deserialize(m_ClientStream));
                    handleComunication(inObject);
                    
                }
                catch(Exception e )
                {
                    if(!m_Client.Connected)
                    {
                        Console.WriteLine("Client number {0} is left the server", m_ClientNumber);
                    }
                    break;
                    
                }       
            }
            m_Client.Close();
        }

        private void handleComunication(InConnectionObject connectionObject)
        {
            executeRequest(connectionObject);
            OutConnectionObject responce = null;
            responce = m_MethodExecuter.IsExecutedOk() ? dealWithCorrectExecution() : dealWithErrorInExecution();
            respondToClient(responce);
        }

        private void respondToClient(OutConnectionObject outConnection)
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            binaryFormatter.Serialize(m_ClientStream, outConnection);
            m_ClientStream.Flush();
        }

        protected abstract OutConnectionObject dealWithCorrectExecution();

        protected abstract OutConnectionObject dealWithErrorInExecution();

        protected abstract void executeRequest(InConnectionObject connectionObject);




        #region Stam
        protected byte[] ObjectToByteArray(object _Object)
        {
            try
            {
                // create new memory stream
                MemoryStream _MemoryStream = new MemoryStream();

                // create new BinaryFormatter
                BinaryFormatter _BinaryFormatter = new BinaryFormatter();

                // Serializes an object, or graph of connected objects, to the given stream.
                _BinaryFormatter.Serialize(_MemoryStream, _Object);

                // convert stream to byte array and return
                return _MemoryStream.ToArray();
            }
            catch (Exception _Exception)
            {
                // Error
                Console.WriteLine("Exception caught in process: {0}", _Exception.ToString());
            }

            // Error occured, return null
            return null;
        }

        protected object ByteArrayToObject(byte[] _ByteArray)
        {
            try
            {
                // convert byte array to memory stream
                MemoryStream _MemoryStream = new MemoryStream(_ByteArray);

                // create new BinaryFormatter
                BinaryFormatter _BinaryFormatter = new BinaryFormatter();

                // set memory stream position to starting point
                _MemoryStream.Position = 0;

                // Deserializes a stream into an object graph and return as a object.
                return _BinaryFormatter.Deserialize(_MemoryStream);
            }
            catch (Exception _Exception)
            {
                // Error
                Console.WriteLine("Exception caught in process: {0}", _Exception.ToString());
            }

            // Error occured, return null
            return null;
        }

        #endregion

    }
}
